#include "stdafx.h"
#include "ChipBus.h"

ChipBus* ChipBus::Create(HANDLE hQuit)
{
	return new ChipBus(hQuit);
}

ChipBus::ChipBus(HANDLE hQuit)
:m_hQuit(hQuit)
,m_hEvent(::CreateEvent(NULL,TRUE,FALSE,NULL))
,m_current(0)
,m_end(0)
{
}

ChipBus::~ChipBus()
{
	::CloseHandle(m_hEvent);
	m_hEvent = 0;
}

void ChipBus::Push(ChipMessage const& message)
{
	m_csLock.Lock();
	memcpy(m_message+(m_end%DATA_CAPACITY), &message, sizeof(ChipMessage));
	++m_end;
	m_csLock.Unlock();
	::SetEvent(m_hEvent);
}

ChipMessage& ChipBus::Pop(bool& quitFlag)
{
	quitFlag = false;
	HANDLE handles[] = {m_hEvent, m_hQuit};
	while (true)
	{
		DWORD rtn = ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
		if (WAIT_OBJECT_0 == rtn)
		{
			m_csLock.Lock();
			if (IsEmpty())
			{
				m_csLock.Unlock();
				continue;
			}
			break;
		}
		else
		{
			quitFlag = true;
			return m_message[0];
		}
	}

	ChipMessage& message = m_message[m_current%DATA_CAPACITY];
	++m_current;
	if (IsEmpty())
	{
		::ResetEvent(m_hEvent);
	}
	m_csLock.Unlock();

	return message;
}

bool ChipBus::IsApcPop(bool& quitFlag, ChipMessage& message)
{
	quitFlag = false;
	HANDLE handles[] = {m_hEvent, m_hQuit};
	while(true)
	{
		DWORD rtn = ::WaitForMultipleObjectsEx(2, handles, FALSE, INFINITE, TRUE);
		if (WAIT_OBJECT_0 == rtn)
		{
			m_csLock.Lock();
			if (IsEmpty())
			{
				m_csLock.Unlock();
				continue;
			}
			break;
		}
		else if (WAIT_IO_COMPLETION == rtn)
		{
			return true;
		}
		else
		{
			quitFlag = true;
			message = m_message[0];
			return false;
		}
	}

	message = m_message[m_current%DATA_CAPACITY];
	++m_current;
	if (IsEmpty())
	{
		::ResetEvent(m_hEvent);
	}
	m_csLock.Unlock();

	return false;
}